package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.swing.plaf.synth.ColorType;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author Yandel
 * @since 2025-05-16
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {

    private final IInteractionReplyService replyService;

    private final UserClient userClient;// 远程调用用户服务
    private final SearchClient searchClient;// 远程调用搜索服务
    private final CourseClient courseClient;// 远程调用课程服务
    private final CatalogueClient catalogueClient;//  远程调用课程章节服务
    private final CategoryCache categoryCache;//缓存中读取分类信息

    @Override
    public void saveQuestion(QuestionFormDTO dto) {
        //1、获取当前用户id
        Long userId = UserContext.getUser();
        //2、DTO转po
        InteractionQuestion question = BeanUtils.copyBean(dto, InteractionQuestion.class);
        question.setUserId(userId);
        //3、保存
        this.save(question);
    }

    @Override
    public void updateQuestion(Long id, QuestionFormDTO dto) {
        //1.校验
        if (StringUtils.isBlank(dto.getTitle())
                || StringUtils.isBlank(dto.getDescription())
                || dto.getAnonymity() == null) {
            throw new BadRequestException("非法参数~");
        }

        //2.校验id
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("非法参数~");
        }
        //只能修改自己的问题
        if (!question.getUserId().equals(UserContext.getUser())) {
            throw new BadRequestException("不能修改别人的互动问题~");
        }


        //3.dto 转po
        question.setTitle(dto.getTitle());
        question.setDescription(dto.getDescription());
        question.setAnonymity(dto.getAnonymity());

        //4.更新
        this.updateById(question);
    }


    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
        //1.校验 参数courseID
        if (query.getCourseId() == null && query.getSectionId() == null) {
            throw new BadRequestException("课程id不能为空~");
        }

        //2.获取登录用户id
        Long userId = UserContext.getUser();


        //3.分页查询互动问题 interaction_question  条件：courseId    onlyMine 为true 才会加userId
        // 小节id不为空  hidden 为false   分页查询  结果按提问时间倒序
        //匿名内部类
        Page<InteractionQuestion> page = this.lambdaQuery()
//                .select(InteractionQuestion::getId,InteractionQuestion::getTitle,InteractionQuestion::getCourseId)
//                .select(InteractionQuestion.class, new Predicate<TableFieldInfo>() {//匿名内部类
//                    @Override
//                    public boolean test(TableFieldInfo tableFieldInfo) {
////                        tableFieldInfo.getProperty();//获取属性名
//                        return !tableFieldInfo.getProperty().equals("description");//指定  不查的字段（ ）
//                    }
//                })

                // lambda简化
                .select(InteractionQuestion.class, tableFieldInfo -> !tableFieldInfo.getProperty().equals("description"))//排除description字段
                .eq(InteractionQuestion::getCourseId, query.getCourseId())
                .eq(query.getOnlyMine(), InteractionQuestion::getUserId, userId)
                .eq(query.getSectionId() != null, InteractionQuestion::getSectionId, query.getSectionId())
                .eq(InteractionQuestion::getHidden, false)
//                .page(query.toMpPage("create_time",false))
                .page(query.toMpPageDefaultSortByCreateTimeDesc());

        //查询的结果
        List<InteractionQuestion> records = page.getRecords();

        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        //互动问题的 最新回答id集合
        Set<Long> latestAnswerIds = new HashSet<>();
        Set<Long> userIds = new HashSet<>();  //互动问题的用户id集合
        for (InteractionQuestion record : records) {
            //添加用户id集合
            if (!record.getAnonymity()) {
                userIds.add(record.getUserId());
            }

            //添加最新回答id集合
            Long latestAnswerId = record.getLatestAnswerId();
            if (latestAnswerId != null) {
                latestAnswerIds.add(latestAnswerId);
            }
        }
        //Stream流写法
//        Set<Long> latestAnswerIds = records.stream()
//                .map(InteractionQuestion::getLatestAnswerId)
//                .filter(latestAnswerId -> latestAnswerId !=null)
//                .collect(Collectors.toSet());


        //4.根据最新回答id 批量查询回答信息 ->查询interaction_reply表       条件latestAnswerIds

        //查询回答者的map对象集合    interaction_reply表    条件->interaction_question中的latestAnswerId 和 interaction_reply中的主键id关联
        Map<Long, InteractionReply> replyMap = new HashMap<>();
        if (CollUtils.isNotEmpty(latestAnswerIds)) {//集合可能为空，需要做非空校验
//            List<InteractionReply> replyList = replyService.listByIds(latestAnswerIds);
            List<InteractionReply> replyList = replyService.list(Wrappers.<InteractionReply>lambdaQuery()
                    .in(InteractionReply::getId, latestAnswerIds)//interaction_question中的latestAnswerId 和 interaction_reply中的主键id关联
                    .eq(InteractionReply::getHidden, false));//查询非隐藏的回答【管理端可能会隐藏回答信息】
            //list 转成map集合
            for (InteractionReply reply : replyList) {

                if (!reply.getAnonymity()) {//如果回答者不是匿名的，则把回答者的id添加到userIds中
                    userIds.add(reply.getUserId());//将最新回答者id  添加到userIds中
                }

                replyMap.put(reply.getId(), reply);
            }

            //stream 流写法
//            Map<Long, InteractionReply> replyMap1 = replyList.stream()
//                    .collect(Collectors.toMap(InteractionReply::getId, reply -> reply));
        }


        //5.远程调用用户服务  获取用户信息  [批量]
        List<UserDTO> userList = userClient.queryUserByIds(userIds);
        //userList 转成map集合
        Map<Long, UserDTO> userDTOMap = userList.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));


        //6.封装VO
        List<QuestionVO> voList = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionVO vo = BeanUtils.copyBean(record, QuestionVO.class);
            if (!vo.getAnonymity()) {//提问者是否匿名，如果不匿名，则需要把提问者的昵称和头像返回给前端
                UserDTO userDTO = userDTOMap.get(record.getUserId());
                if (userDTO != null) {
                    vo.setUserName(userDTO.getName());
                    vo.setUserIcon(userDTO.getIcon());
                }

            } else {
                vo.setUserName("匿名用户");
            }

            //latestAnswerId 和 reply中的id对应
            InteractionReply reply = replyMap.get(record.getLatestAnswerId());
            if (reply != null) {
                if (!reply.getAnonymity()) {//如果最近回答是非匿名的，才需要把最新回答者的昵称返回给前端

                    UserDTO userDTO = userDTOMap.get(record.getUserId());
                    if (userDTO != null) {
                        vo.setLatestReplyUser(userDTO.getName()); //最新回答者的昵称
                    }
                }
                vo.setLatestReplyContent(reply.getContent());//最新回答信息
            }

            voList.add(vo);
        }

        return PageDTO.of(page, voList);
    }

    @Override
    public QuestionVO queryQuestionById(Long id) {
        //1.校验
        if (id == null) {
            throw new BadRequestException("参数错误~");
        }
        //2.查询互动问题表   按主键查询
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在~");
        }

        //3.如果该问题管理员设置了隐藏   返回空
        if (question.getHidden()) {
            return null;
        }
        //4.封装VO
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);

        //5.如果用户是匿名提问，不用查询提问者昵称和头像
        if (!question.getAnonymity()) {
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            if (userDTO != null) {
                questionVO.setUserName(userDTO.getName());
                questionVO.setUserIcon(userDTO.getIcon());
            }
        }

        return questionVO;
    }


    @Override
    public void deleteQuestionById(Long id) {
        //1、查询问题是否存在
        if (id == null) {
            throw new BadRequestException("非法参数~");
        }
        //2、判断是否是当前用户提问的
        //查询当前用户
        Long userId = UserContext.getUser();
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            return;
        }
        //如果不是则报错
        if (!question.getUserId().equals(userId)) {
            throw new BadRequestException("无权删除他人的问题~");
        } else {
            //如果是则删除问题
            this.removeById(id);
            //3、然后删除问题下的回答及评论
            replyService.remove(Wrappers.<InteractionReply>lambdaQuery()
                    .eq(InteractionReply::getQuestionId, id));
        }

    }

    @Override
    public PageDTO<QuestionAdminVO> queryQuestionAdminPage(QuestionAdminPageQuery query) {

        //0.如果、用户传了课程的参数  则从es中获取该名称对应的课程id
        String courseName = query.getCourseName();
        List<Long> coursesIds = null;
        if (StringUtils.isNotBlank(courseName)) {
            coursesIds = searchClient.queryCoursesIdByName(courseName);//通过feign远程调用搜所服务，从es中搜所关键字对应的课程id
            if (CollUtils.isEmpty(coursesIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }

        //1、查询互动问题表   条件前端传条件就添加条件     分页    排序安装提问时间倒序
        Page<InteractionQuestion> page = this.lambdaQuery()
                .in(CollUtils.isNotEmpty(coursesIds), InteractionQuestion::getCourseId, coursesIds)
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())//管理端问题状态：0-未查看，1-已查看
                .between(query.getBeginTime() != null && query.getEndTime() != null,//条件：时间区间
                        InteractionQuestion::getCreateTime, query.getBeginTime(), query.getEndTime())//表示创建时间在这个区间
                .page(query.toMpPageDefaultSortByCreateTimeDesc());

        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(0L, 0L);
        }
        Set<Long> uids = new HashSet<>();//用户ID集合
        Set<Long> courseIds = new HashSet<>();//课程id集合
        Set<Long> chapterAndSectionIds = new HashSet<>();//章和节id集合
        for (InteractionQuestion record : records) {
            uids.add(record.getUserId());
            courseIds.add(record.getCourseId());
            chapterAndSectionIds.add(record.getChapterId());
            chapterAndSectionIds.add(record.getSectionId());
        }

        //2、远程调用用户服务  获取用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(uids);
        if (CollUtils.isEmpty(userDTOS)) {
            throw new BizIllegalException("用户不存在");
        }
        //list 转 map
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));

        //3.远程调用课程服务获取课程信息
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(simpleInfoList)) {
            throw new BizIllegalException("课程不存在");
        }
        //List 转 map
        Map<Long, CourseSimpleInfoDTO> courseSimpleInfoDTOMap = simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        //4.远程调用课程服务获取章节信息
        List<CataSimpleInfoDTO> cataSimpleInfoDTOList = catalogueClient.batchQueryCatalogue(chapterAndSectionIds);
        if (CollUtils.isEmpty(cataSimpleInfoDTOList)) {
            throw new BizIllegalException("章节不存在");
        }
        //list 转 map                                                   <id,name>
        Map<Long, String> cateInfoDTO = cataSimpleInfoDTOList
                .stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));


        //6.封装vo返回
        List<QuestionAdminVO> voList = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionAdminVO adminVO = BeanUtils.copyBean(record, QuestionAdminVO.class);

            UserDTO userDTO = userDTOMap.get(record.getUserId());
            if (userDTO != null) {
                adminVO.setUserName(userDTO.getName());//提问者昵称
            }

            CourseSimpleInfoDTO courseSimpleInfoDTO = courseSimpleInfoDTOMap.get(record.getCourseId());
            if (courseSimpleInfoDTO != null) {
                adminVO.setCourseName(courseSimpleInfoDTO.getName());//课程名称

                List<Long> categoryIds = courseSimpleInfoDTO.getCategoryIds();//一二三级分类id集合
                //获取课程一二三级分类id
                String categoryNames = categoryCache.getCategoryNames(categoryIds);
                //5.获取分类信息
                adminVO.setCategoryName(categoryNames);//分类名称,拼接字段
            }

            adminVO.setChapterName(cateInfoDTO.get(record.getChapterId()));//章名称
            adminVO.setSectionName(cateInfoDTO.get(record.getSectionId()));//节名称


            voList.add(adminVO);
        }
        return PageDTO.of(page, voList);
    }


    @Override
    public QuestionAdminVO queryQuestionAdminById(Long id) {
        //1、校验参数
        if (id == null) {
            throw new BizIllegalException("参数id不能为空");
        }

        //2、查询interaction_question表
        InteractionQuestion question = this.getById(id);
        log.info("查询结果，question={}", question);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }

        //拷贝基本信息
        QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);//基本信息拷贝 ,没有显示回答数量，课程负责老师
        //3、远程调用用户服务  获取用户信息
        UserDTO userDTO = userClient.queryUserById(question.getUserId());
        if (userDTO == null) {
            throw new BizIllegalException("用户不存在");
        }else{
            log.info("userDTO={}" , userDTO);
            vo.setUserName(userDTO.getName());//提问者昵称
            vo.setUserIcon(userDTO.getIcon());//提问者头像
            vo.setAnswerAmount(question.getAnswerTimes());//回答数量
        }

        //4、远程调用课程服务获取课程信息
        CourseFullInfoDTO courseFullInfoDTO = courseClient.getCourseInfoById(question.getCourseId(), false, true);
        if (courseFullInfoDTO != null){
            //设置课程名称
            vo.setCourseName(courseFullInfoDTO.getName());
           //设置老师昵称
            List<Long> teacherIds = courseFullInfoDTO.getTeacherIds();
            if (CollUtils.isEmpty(teacherIds)){
                throw new BizIllegalException("教师不存在~");
            }
            List<UserDTO> teachersDTO = userClient.queryUserByIds(teacherIds);
            log.info("teachersDTO={}" , teachersDTO);
            if (CollUtils.isNotEmpty(teachersDTO)){
                String teacherName = teachersDTO
                        .stream()
                        .map(UserDTO::getName)
                        .collect(Collectors.joining("/"));//将所有名字用 / 拼接在一起，得到一个最终的字符串
                log.info("teacherName={}" , teacherName);
//                vo.setUserName(teacherName);//重名覆盖
                vo.setTeacherName(teacherName);

            }
            //获取分类名称——从缓存中获取
            vo.setCategoryName(categoryCache.getCategoryNames(courseFullInfoDTO.getCategoryIds()));
        }
        //5、远程调用课程服务获取章节信息
        Set<Long> chapterAndSectionIds = new HashSet<>();//章和节id集合
        chapterAndSectionIds.add(question.getChapterId());//章
        chapterAndSectionIds.add(question.getSectionId());//节
        List<CataSimpleInfoDTO> cataSimpleInfoDTOList = catalogueClient.batchQueryCatalogue(chapterAndSectionIds);//根据目录id列表查询目录信息
        if (CollUtils.isEmpty(cataSimpleInfoDTOList)){
            throw new BizIllegalException("章节不存在");
        }
        //list 转成map
        Map<Long, String> cateSimpleDTOs = cataSimpleInfoDTOList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, c -> c.getName()));
        log.info("cateSimpleDTOs:{}",cateSimpleDTOs);//cateSimpleDTOs:{17=第一章 带你玩-第2课, 15=第一章 带你玩}
        vo.setChapterName(cateSimpleDTOs.get(question.getChapterId()));//章
        vo.setSectionName(cateSimpleDTOs.get(question.getSectionId()));//节

        //7、查看完成，将问题status标记为已查看
        question.setStatus(QuestionStatus.CHECKED);

        //返回vo
        return vo;
    }

    @Override
    public void hideOrShowQuestion(Long id, Boolean hidden) {
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }
        question.setHidden(hidden);
        boolean result = this.updateById(question);
        if (!result) {
            throw new BizIllegalException("问题隐藏失败~");
        }


    }
}
